import { build, stop, Plugin } from "https://deno.land/x/esbuild@v0.20.0/mod.js"; import { denoResolverPlugin, denoLoaderPlugin } from "https://deno.land/x/esbuild_deno_loader@0.9.0/mod.ts"; import { gray } from "https://deno.land/std@0.215.0/fmt/colors.ts"; import { toFileUrl } from "https://deno.land/std@0.213.0/path/mod.ts"; /** keyが親ファイルパス, valueがそのファイルでimportしたファイルのパスリスト */ const ancestors = new Map; let entryPoint = ""; function* makeTree( parent: string, // parentからの相対URLで表示したいときtrue relative?: boolean, viewedPath?: Set, ): Generator { const childs = ancestors.get(parent); if (!childs) return; viewedPath ??= new Set(); viewedPath.add(parent); for (let i = 0; i < childs.length; i++) { const child = childs[i]; const relativePath = decodeURIComponent( relative ? makeRelative(new URL(parent), new URL(child)) : child, ); const lastOne = i + 1 === childs.length; const branch = lastOne ? "└─ " : "├─ "; // 一度読み込んだものは灰色で表示する if (viewedPath.has(child)) { yield `${branch}${gray(relativePath)}`; continue; } yield `${branch}${relativePath}`; viewedPath.add(child); const indent = lastOne ? " " : "│ "; for (const line of makeTree(child, relative ?? false, viewedPath)) { yield `${indent}${line}`; } } } const listPlugin: Plugin = { name: "list-imports", setup: ({ onResolve, resolve }) => { onResolve({ filter: /.*/, }, (args) => { /** * The following codes come from https://github.com/lucacasonato/esbuild_deno_loader/blob/0.9.0/src/plugin_deno_resolver.ts * Copyright (c) 2021 Luca Casonato. All rights reserved. MIT license. */ // // The first pass resolver performs synchronous resolution. This // includes relative to absolute specifier resolution and import map // resolution. // We have to first determine the referrer URL to use when resolving // the specifier. This is either the importer URL, or the resolveDir // URL if the importer is not specified (ie if the specifier is at the // root). let referrer: URL; if (args.importer !== "") { if (args.namespace === "") { throw new Error("[assert] namespace is empty"); } referrer = new URL(`${args.namespace}:${args.importer}`); } else if (args.resolveDir !== "") { referrer = new URL(`${toFileUrl(args.resolveDir).href}/`); } else { return undefined; } // We can then resolve the specifier relative to the referrer URL. If // an import map is specified, we use that to resolve the specifier. const resolved = new URL(args.path, referrer); if (args.kind === "entry-point") { entryPoint = resolved.href; } else { ancestors.set( referrer.href, [...(ancestors.get(referrer.href) ?? []), resolved.href] ); } return undefined; }); }, }; await build({ plugins: [listPlugin, denoResolverPlugin(), denoLoaderPlugin()], entryPoints: [Deno.args[0]], bundle: true, write: false, format: "esm", minify: true, charset: "utf8", }); stop(); console.log(entryPoint); for (const line of makeTree(entryPoint)) { console.log(line); }